package com.example.glgk.service.report;

import com.example.glgk.dto.UserInfo;
import org.springframework.core.io.Resource;
import com.example.glgk.dto.report.*;
import com.example.glgk.entity.ElementDataEntity;
import com.example.glgk.entity.report.*;
import com.example.glgk.mapper.*;
import com.example.glgk.optionenum.OperationStatus;
import com.example.glgk.optionenum.ProcessStatus;
import com.example.glgk.optionenum.TaskStatus;
import com.example.glgk.utils.Calculator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.multipart.MultipartFile;
import java.net.MalformedURLException;

import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lxk
 */
@Service
@Slf4j
public class ReportService {

    @Autowired
    private ReportMapper reportMapper;

    @Autowired
    private IndicatorDataMapper indicatorDataMapper;

    @Autowired
    private ReportTaskMapper reportTaskMapper;

    @Autowired
    private ElementDataMonthMapper elementDataMonthMapper;


    @Transactional(rollbackFor = Exception.class)
    public List<ReportEntity> save(List<ReportDto> reportDtos) {
        List<ReportEntity> list = new ArrayList<>();
        if(reportDtos.get(0).getId() != null){
             return update(reportDtos);
        }else{
/*            ReportTaskEntity reportTaskEntity = reportMapper.queryReportTaskById(reportDtos.get(0).getTaskId());
            reportTaskEntity.setStartTime(new Date());
            reportMapper.updateReportTaskStartTime(reportTaskEntity);*/
        }
        for (ReportDto reportDto : reportDtos) {
            ReportEntity reportEntity =  ReportEntity.builder().build();
            BeanUtils.copyProperties(reportDto,reportEntity);
            reportEntity.setProcessStatus(ProcessStatus.DEFT);
            reportEntity.setCreatedTime(new Date());
            reportMapper.save(reportEntity);
            list.add(reportEntity);
        }

        return list;

    }

    /**
     * 时间根本来不及而且就这一个接口，所以不用审批流，后续有时间，再来集成修改
     * @param reportDtos
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean submit(List<ReportDto> reportDtos) {
        log.info("参数：{}",reportDtos);
        List<ReportEntity> entities = new ArrayList<>();
        if(reportDtos.get(0).getProcessStatus() == null){
            //说明还没有保存过，那么先保存
            entities = save(reportDtos);
        }else{
            //说明保存过了，可能进行了修改
            entities = update(reportDtos);
        }
        //启动流程，开始修改审批状态
        for (ReportEntity entity : entities) {
            entity.setProcessStatus(ProcessStatus.PROCESSING);
            reportMapper.update(entity);
        }

        //往记录表插入一条数据
        int taskId = reportDtos.get(0).getTaskId();
        OperationHistoryEntity operationHistoryEntity =  OperationHistoryEntity.builder()
                .taskId(taskId)
                .operationTime(new Date())
                .operationUserId(reportDtos.get(0).getInitiateUserId())
                .status(OperationStatus.SUBMIT.getValue())
                .build();
        reportMapper.insertHistory(operationHistoryEntity);

        //同样要修改任务表里的数据
        ReportTaskEntity reportTaskEntity = reportTaskMapper.selectById(taskId);
        reportTaskEntity.setStartTime(new Date());
        reportTaskEntity.setTaskStatus(TaskStatus.PROGRESSING.getValue());
        reportTaskEntity.setProcessStatus(ProcessStatus.PROCESSING.getValue());
        reportTaskMapper.update(reportTaskEntity);

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public List<ReportEntity> update(List<ReportDto> reportDtos) {
        List<ReportEntity> list = new ArrayList<>();
        for (ReportDto reportDto : reportDtos) {
            ReportEntity reportEntity =  ReportEntity.builder().build();
            BeanUtils.copyProperties(reportDto,reportEntity);
            reportMapper.update(reportEntity);
            list.add(reportEntity);
        }
        return list;


    }

    private void getBeforeTime(ReportSearchDto search) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        String time = search.getTime();
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(sdf.parse(time));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        calendar.add(Calendar.YEAR, -1);
        String beforeTime = sdf.format(calendar.getTime());
        String[] split = time.split("-");
        String beforeYear = String.valueOf(Integer.parseInt(split[0])-1);
        search.setBeforeTime(beforeTime);
        search.setBeforeYear(beforeYear);

    }

    @Transactional(rollbackFor = Exception.class)
    public void operation(List<ReportDto> reportDtos) {
        List<ReportEntity> entities = new ArrayList<>();
        for (ReportDto reportDto : reportDtos) {
            ReportEntity reportEntity =  ReportEntity.builder().build();
            BeanUtils.copyProperties(reportDto,reportEntity);
            reportEntity.setApprovedTime(new Date());
            if(reportDto.getFlag()){
                reportEntity.setProcessStatus(ProcessStatus.PROCESSED);
            }else{
                reportEntity.setProcessStatus(ProcessStatus.REJECT);
            }
            reportMapper.update(reportEntity);
            entities.add(reportEntity);
        }

        //往记录表插入一条数据
        int taskId = reportDtos.get(0).getTaskId();
        OperationHistoryEntity operationHistoryEntity =  OperationHistoryEntity.builder()
                .taskId(taskId)
                .operationTime(new Date())
                .operationUserId(reportDtos.get(0).getApprovedUserId())
                .status(reportDtos.get(0).getFlag() ? OperationStatus.PROCESSED.getValue() : OperationStatus.REJECT.getValue())
                .operationComment(reportDtos.get(0).getApprovedComment())
                .build();
        reportMapper.insertHistory(operationHistoryEntity);

        //在审批完成后，都要把任务结束时间修改、状态、审批状态修改
        ReportTaskEntity reportTaskEntity = reportTaskMapper.selectById(taskId);
        reportTaskEntity.setEndTime(new Date());
        reportTaskEntity.setTaskStatus(TaskStatus.END.getValue());
        reportTaskEntity.setProcessStatus(reportDtos.get(0).getFlag() ? ProcessStatus.PROCESSED.getValue() : ProcessStatus.REJECT.getValue());
        reportTaskMapper.update(reportTaskEntity);

    }

    public List<ReportTaskDto> getTask(TaskSearchDto taskSearchDto) {
        //todo 领导查询的时候，只查进行中、已审批的任务
        List<ReportTaskDto> list = new ArrayList<>();
        List<ReportTaskEntity> taskList = reportMapper.queryTask(taskSearchDto);
        for (ReportTaskEntity reportTaskEntity : taskList) {
            ReportTaskDto reportTaskDto = ReportTaskDto.builder().build();
            BeanUtils.copyProperties(reportTaskEntity,reportTaskDto);
            reportTaskDto.setTaskStatus(TaskStatus.getEnumByValue(reportTaskEntity.getTaskStatus()));
            reportTaskDto.setTaskStatusText(reportTaskDto.getTaskStatus().getText());
            reportTaskDto.setProcessStatus(ProcessStatus.getEnumByValue(reportTaskEntity.getProcessStatus()));
            reportTaskDto.setProcessStatusText(reportTaskDto.getProcessStatus().getText());
            list.add(reportTaskDto);
        }

        return list.stream()
                .sorted(Comparator.comparing(ReportTaskDto::getTaskTime).reversed())
                .collect(Collectors.toList());
    }


    public List<String> getTaskNames(UserInfo userInfo) {
        return reportMapper.getTaskNames(userInfo);
    }

    @Autowired
    ElementDataMapper elementDataMapper;

    public List<ReportDto> searchPlus(ReportSearchDto search){
        //如果能在REPORT_DATA里面根据任务查到数据就不需要自己填充
        List<ReportDto> reportDtosEntries = reportMapper.queryByTaskId(search);
        if(!CollectionUtils.isEmpty(reportDtosEntries)){
            for (ReportDto reportDto : reportDtosEntries) {
                reportDto.setProcessStatusText(reportDto.getProcessStatus().getText());
            }
            return reportDtosEntries;
        }
        List<ReportDto> reportDtos = new ArrayList<>();
        //设置一下同期时间和去年年份
        getBeforeTime(search);
        log.info("同期时间:{}",search.getBeforeTime(),"去年年份:{}",search.getBeforeYear());
        //查询出当前部门负责哪些指标（元素）
//        List<String> indicators = indicatorDataMapper.selectByUser(search);
        List<IndicatorDto> indicatorDatas =  indicatorDataMapper.selectByDept(search);
        //求出这些指标的元素id
        List<String> elementIds = getAllElementIds(indicatorDatas);
        //确认一下元素的数据来源 元素数据
        List<ElementDataEntity> query = elementDataMapper.query(elementIds);
        //确定不同数据来源
        List<String> dayElementIds = query.stream().filter(s -> StringUtils.isNotBlank(s.getDataTable()) && "1".equals(s.getDataTable())).map(ElementDataEntity::getId).collect(Collectors.toList());
        List<String> monthElementIds =  query.stream().filter(s -> StringUtils.isNotBlank(s.getDataTable()) && "2".equals(s.getDataTable())).map(ElementDataEntity::getId).collect(Collectors.toList());
        List<String> reportElementIds = query.stream().filter(s -> StringUtils.isNotBlank(s.getDataTable()) && "3".equals(s.getDataTable())).map(ElementDataEntity::getId).collect(Collectors.toList());
        //查询这些元素值中三个不同时间的维度的指标值 查今年的指标值
        QueryIndexEntity indexEntity = QueryIndexEntity.builder().elementIds(dayElementIds).time(search.getTime()).wardName(search.getUserInfo().getWardName()).timeNode("month").build();
        List<ElementEntity> elementDataEntities1=indicatorDataMapper.queryIndexValue(indexEntity); // 天表的数据
        indexEntity.setElementIds(monthElementIds);
        List<ElementEntity> elementDataEntities2 = elementDataMonthMapper.queryIndexValue(indexEntity); //月表的数据
        indexEntity.setElementIds(reportElementIds);
        List<ElementEntity> elementDataEntities3 =reportMapper.queryIndexValue(indexEntity); //填报表的数据
        Map<String, String> mapValue = new HashMap<>();
        List<ElementEntity> elementDataEntities = new ArrayList<>();
        elementDataEntities.addAll(elementDataEntities1);
        elementDataEntities.addAll(elementDataEntities2);
        elementDataEntities.addAll(elementDataEntities3);
        for (ElementEntity elementDataEntity : elementDataEntities) {
            mapValue.put("${"+elementDataEntity.getElementId()+"}", String.valueOf(elementDataEntity.getValue()));
        }
        //
        QueryIndexEntity indexEntity2 = QueryIndexEntity.builder().elementIds(dayElementIds).time(search.getBeforeTime()).wardName(search.getUserInfo().getWardName()).timeNode("month").build();
        List<ElementEntity> elementDataEntities4=indicatorDataMapper.queryIndexValue(indexEntity2);
        indexEntity2.setElementIds(monthElementIds);
        List<ElementEntity> elementDataEntities5 = elementDataMonthMapper.queryIndexValue(indexEntity2); //月表的数据
        indexEntity2.setElementIds(reportElementIds);
        List<ElementEntity> elementDataEntities6 =reportMapper.queryIndexValue(indexEntity2);
        Map<String, String> mapValue2 = new HashMap<>();
        List<ElementEntity> elementDataEntitiesYoy = new ArrayList<>();
        elementDataEntitiesYoy.addAll(elementDataEntities4);
        elementDataEntitiesYoy.addAll(elementDataEntities5);
        elementDataEntitiesYoy.addAll(elementDataEntities6);
        for (ElementEntity elementDataEntity : elementDataEntitiesYoy) {
            mapValue2.put("${"+elementDataEntity.getElementId()+"}", String.valueOf(elementDataEntity.getValue()));
        }
        //
        QueryIndexEntity indexEntity3 = QueryIndexEntity.builder().elementIds(dayElementIds).time(search.getBeforeYear()).wardName(search.getUserInfo().getWardName()).timeNode("year").build();
        List<ElementEntity> elementDataEntities7=indicatorDataMapper.queryIndexValue(indexEntity3);
        indexEntity3.setElementIds(monthElementIds);
        List<ElementEntity> elementDataEntities8 = elementDataMonthMapper.queryIndexValue(indexEntity3); //月表的数据
        indexEntity3.setElementIds(reportElementIds);
        List<ElementEntity> elementDataEntities9 =reportMapper.queryIndexValue(indexEntity3);
        Map<String, String> mapValue3 = new HashMap<>();
        List<ElementEntity> elementDataEntitiesBefore = new ArrayList<>();
        elementDataEntitiesBefore.addAll(elementDataEntities7);
        elementDataEntitiesBefore.addAll(elementDataEntities8);
        elementDataEntitiesBefore.addAll(elementDataEntities9);
        for (ElementEntity elementDataEntity : elementDataEntitiesBefore) {
            mapValue3.put("${"+elementDataEntity.getElementId()+"}", String.valueOf(elementDataEntity.getValue()));
        }

        for (IndicatorDto indicatorData : indicatorDatas) {
            ReportDto reportDto = ReportDto.builder()
                    .elementId(indicatorData.getIds())
                    .project(indicatorData.getIndexCode() + indicatorData.getName())
                    .indexDefine(indicatorData.getIndexDesc())
                    .deptName(search.getUserInfo().getWardName())
                    .unit(indicatorData.getUnit())
                    .time(search.getTime())
                    .initiateUserId(search.getUserInfo().getUserId())
                    .indicatorId(indicatorData.getId())
                    .formula(indicatorData.getFormula())
                    .ids(indicatorData.getIds())
                    .handFill(indicatorData.getHandFill()).build();
            //解析当前指标的公式，通过元素值计算指标值
            String formula = indicatorData.getFormula();
            String indexValue = Calculator.conversionToSting(formula, mapValue);//当前指标值
            String indexValue2 = Calculator.conversionToSting(formula, mapValue2);//同期指标值
            String indexValue3 = Calculator.conversionToSting(formula, mapValue3);//去年指标值

            reportDto.setIndicatorValue(indexValue);
            reportDto.setSamePeriodValue(indexValue2);
            reportDto.setSamePeriodYearValue(indexValue3);
            reportDto.setTaskId(search.getTaskId());
            reportDtos.add(reportDto);
        }
        return reportDtos;
    }


    /**
     * 查询指标（元素）在总的元素ids
     *
     * @param list
     * @return
     */
    public List<String> getAllElementIds(List<IndicatorDto> list) {
        if (org.springframework.util.CollectionUtils.isEmpty(list)) {
            return null;
        }
        //把list里面的ids全部单拎出来，去重，然后查询把所有的元素id查出来 但是还是要分月表，天表，手填表 所以数据源list应该分类，暂时只考虑天表，月表
        List<String> elementIds = new ArrayList<>();
        for (IndicatorDto indicatorDataEntity : list) {
            if (StringUtils.isNotBlank(indicatorDataEntity.getIds())) {
                String[] split = indicatorDataEntity.getIds().split(",");
                elementIds.addAll(Arrays.asList(split));
            }
        }
        if (elementIds.isEmpty()) {
            return null;
        }
        elementIds = elementIds.stream().distinct().collect(Collectors.toList());
        return elementIds;
    }


    public List<OperationHistoryDto> searchHistory(Integer taskId) {
        List<OperationHistoryEntity> list = reportMapper.searchHistory(taskId);
        List<OperationHistoryDto> result = new ArrayList<>();
        list.forEach(s->{
            OperationHistoryDto operationHistoryDto = OperationHistoryDto.builder().build();
            BeanUtils.copyProperties(s,operationHistoryDto);
            operationHistoryDto.setStatus(OperationStatus.getEnumByValue(s.getStatus()));
            operationHistoryDto.setStatusText(operationHistoryDto.getStatus().getText());
            result.add(operationHistoryDto);
        });
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public void cancel(List<ReportDto> reportDtos) {
        //撤销 修改填报数据
        for (ReportDto reportDto : reportDtos) {
            ReportEntity entity = ReportEntity.builder().build();
            BeanUtils.copyProperties(reportDto,entity);
            entity.setProcessStatus(ProcessStatus.DEFT);
            reportMapper.update(entity);
        }
        //修改任务数据状态
        int taskId = reportDtos.get(0).getTaskId();
        ReportTaskEntity reportTaskEntity = reportTaskMapper.selectById(taskId);
        if(reportTaskEntity != null){
            reportTaskEntity.setProcessStatus(ProcessStatus.DEFT.getValue());
            reportTaskEntity.setTaskStatus(TaskStatus.START.getValue());
            reportTaskMapper.update(reportTaskEntity);
        }
        //新增审批操作表
        OperationHistoryEntity operationHistoryEntity =  OperationHistoryEntity.builder()
                .taskId(taskId)
                .operationTime(new Date())
                .operationUserId(reportDtos.get(0).getApprovedUserId())
                .status(OperationStatus.CANCEL.getValue())
                .build();
        reportMapper.insertHistory(operationHistoryEntity);
    }



    @Scheduled(cron = "0 0 1 1 * ?")
    @Transactional(rollbackFor = Exception.class)
    public void scheduleTask() throws ParseException {
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int month = calendar.get(Calendar.MONTH) + 1;
        int year = calendar.get(Calendar.YEAR);

        int count=1;
        //查询部门
        List<String> deptList = reportMapper.selectDeptMent();
        for (String dept : deptList) {
                ReportTaskEntity reportTaskEntity = ReportTaskEntity.builder()
                        .deptName(dept)
                        .taskStatus(TaskStatus.START.getValue())
                        .taskName("鼓楼医院" + year + "年" + month + "月绩效填报任务")
                        .processStatus(ProcessStatus.DEFT.getValue())
                        .taskTime(date)
                        .taskId(Integer.parseInt(year + String.format("%02d", month) + String.format("%04d", count)))
                        .build();
                reportTaskMapper.insert(reportTaskEntity);
                count++;
            }

    }

    @Value("${upload.path}")
    private String uploadPath;

    @Transactional(rollbackFor = Exception.class)
    public String upload(MultipartFile[] files, String userId, String deptId,String khzb) throws Exception {
        if(files==null||files.length==0){
            return "文件不能为空！";
        }
        String attachmentId = UUID.randomUUID().toString();
        List<String> fileNameList=new ArrayList<>();
        for(MultipartFile file:files){

            String name = file.getOriginalFilename();
            try{
                Path path = Paths.get(uploadPath, name);
                Files.copy(file.getInputStream(),path);
            }catch (FileAlreadyExistsException e){
                //提示文件已存在
                throw new Exception("文件名重复!");
            }

            assert name != null;
            String[] split = name.split("\\.");

            fileNameList.add(name);
            long size = file.getSize();
        }

        String fileNames=String.join(",",fileNameList);
        AttachmentEntity attachmentEntity = AttachmentEntity.builder()
                .attachmentId(attachmentId) //FJWYBS 附件唯一标识
                .path(uploadPath) //CCLJ 路径
                .createUser(userId) //CJR 创建人
                .dept(deptId) //BM  部门
                .createTime(new Date()) //CJSJ  创建时间
                .name(fileNames) //FJMC  附件名称
                .indicator(khzb)//  考核指标
                //.type(split[1])//FJLX 附件类型
                .type("png")//FJLX 附件类型
                //.size(String.valueOf(size))//FJDX 附件大小
                .size(String.valueOf(5))//FJDX 附件大小
                .build();
        reportMapper.insertFJ(attachmentEntity);
        return fileNames;
    }

    public List<Map<String,String>> getIndicator() {
        return reportMapper.getIndicator();
    }

    public List<Map<String, String>> queryFj(String deptId, List<String> years,List<String>  taskNames) {
        return reportMapper.queryFj(deptId, years,taskNames);
    }

    public List<Map<String, String>> queryAttachments(List<String> list) {
        return reportMapper.queryAttachments(list);
    }


    public List<String> getDataSource() {
        return reportMapper.getDataSource();
    }

    public List<OperationHistoryDto> searchRejectHistory(Integer taskId) {
        List<OperationHistoryEntity> list = reportMapper.searchRejectHistory(taskId);
        List<OperationHistoryDto> result = new ArrayList<>();
        list.forEach(s->{
            OperationHistoryDto operationHistoryDto = OperationHistoryDto.builder().build();
            BeanUtils.copyProperties(s,operationHistoryDto);
            operationHistoryDto.setStatus(OperationStatus.getEnumByValue(s.getStatus()));
            operationHistoryDto.setStatusText(operationHistoryDto.getStatus().getText());
            result.add(operationHistoryDto);
        });
        return result;
    }


}
